home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Explosion
/
Software Explosion (Fore-Matt Home Computing)(1996).iso
/
games
/
workbench
/
battle_sheep
/
source.lha
/
FBS
/
Source
/
sheep.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-16
|
38KB
|
1,255 lines
/* Fuzzy Battle Sheep!
*
* written by John Corigliano with SAS/C 6.51
*
* ⌐1994 John Corigliano
*
* internet: j.corigliano@genie.geis.com
* bix: mopp
*
*/
#define __USE_SYSBASE /* SAS/C - use Absolute Exec Base = 4 */
long __oslibversion = 0; /* SAS/C - auotinit, any library will do */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <devices/audio.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#define MakeID(a,b,c,d) ((LONG)(a)<<24 | (LONG)(b)<<16 | (c)<<8 | (d))
#define ROW_MASK 0x80000000 /* Mask = row 1 */
#define COL_MASK 0x00800000 /* Mask = column 1 */
#define ALL_ROWS 0xFF000000 /* Mask = all rows */
#define ALL_COLS 0x00FFFFFF /* Mask = all columns */
/* Macros to save some typing! */
#define GET_ROW(n) ((n / 24) + 1)
#define GET_COL(n) (n - (((n / 24) * 24) - 1))
#define MAKE_SHIP(n) (ROW_MASK>>(GET_ROW(n)-1))|(COL_MASK>>(GET_COL(n)-1))
struct TextAttr Topaz80 = {"topaz.font", 8, 0, 0,};
#include "placegads.h" /* Contains gadget and menu definitions */
#define NTSC_CLOCK 3579545L /* For sounds */
#define PAL_CLOCK 3546895L
#define OK 0xFF
#define SQUARES 0xC0
/* Each square on the 2 grids will either have
* a number 0-192 or one of these values
*/
#define SUNK 0xFF /* This square holds a destroyed ship */
#define MISS 0xFE /* This square holds nothing */
#define HIT 0xFD /* This square has a ship currently under attack */
/* Colors to draw squares */
#define FRESH 0x0
#define KILL 0x1
#define CURR 0x2
#define SET 0x3
#define EMPTY 0x4
#define TOP 0x1
#define BOTTOM 0x2
#define PLAYER 5
#define COMP 6
#define SLEN 40
#define HORIZ 0x2
/* A struct Ship holds a ULONG that determines its position on the
* grid (Ship.Pos) and a UBYTE that determines its status (Ship.Data)
*
* Ship Position Bits 00000000 00000000 00000000 00000000
* -------- --------------------------
* Rows 1-8 Columns 1 - 24
*
* Ship Data Bits 00000000
* ||||||||_ Sunk
* |||||||__ Orientation (0 = Vert, 1 = Horiz)
* ||||||___ Hits 1 - 6
*/
struct Ship {
ULONG Pos;
UBYTE Data;
};
struct Ship play_ships[] = { /* These are the player's ships */
{0x80FC0000, 0x02},
{0x40F80000, 0x02},
{0x20F00000, 0x02},
{0x10E00000, 0x02},
{0x08C00000, 0x02}
};
struct Ship comp_ships[] = { /* These are the computer's ships */
{0,0},
{0,0},
{0,0},
{0,0},
{0,0}
};
struct noiz { /* Sound info structre */
UBYTE *name; /* file to open */
UBYTE *data; /* sound sample data */
ULONG size; /* size */
UWORD SPS; /* samples per second */
};
struct noiz sounds[] = {
{"sound01", NULL, 0, 0},
{"sound02", NULL, 0, 0},
{"sound03", NULL, 0, 0},
{"sound04", NULL, 0, 0},
{"sound05", NULL, 0, 0},
};
UBYTE sizes[] = {6,5,4,3,2};
UBYTE *Cnames[] = {"Big Daddy","Mathilda","Lamikins","Lil' Sis","Baaa-by"};
UBYTE *Pnames[] = {"Mr. Big", "Sheba", "Wolfy", "Mutt", "Puppy"};
UBYTE *verbs[] = {"killed", "murdered", "destroyed", "annihilated",
"erased", "eradicated", "mutilated", "null and voided",
"got", "pummeled", "iced", "buried", "wiped out",
"shot down","disintegrated", "cut down",
"bludgeoned"};
UBYTE *tk[] = {"dumbest", "average", "smartest"};
UBYTE dead_masks[] = {0xFC, 0xF8, 0xF0 ,0xE0, 0xC0};
UBYTE comp_score = 0, play_score = 0, dir = 0;
UBYTE player[192], computer[192]; /* <-- The two grids !! */
ULONG Raud_dev = 1L, Laud_dev = 1L;
UBYTE think = 2;
BOOL in_progress = FALSE, play_one = FALSE;
/* My fuctoin prototypes */
VOID closer(UBYTE *);
VOID doIDCMP(VOID);
VOID setPlayer(VOID);
VOID dBox(ULONG, SHORT, UBYTE);
VOID moveUp(struct Ship *, WORD);
VOID moveDown(struct Ship *, WORD);
VOID moveLeft(struct Ship *, WORD);
VOID moveRight(struct Ship *, WORD);
BOOL safeDraw(ULONG, ULONG, WORD);
VOID shipRotate(struct Ship *, WORD);
VOID pickShips(struct Ship *);
LONG getRand(LONG);
UBYTE collided(ULONG, ULONG, WORD, struct Ship *);
UBYTE findHit(struct Ship *, ULONG, UBYTE);
BOOL findBlock(UWORD, UWORD);
VOID wText(UBYTE *);
VOID compsTurn(VOID);
BOOL findShort(UBYTE, WORD);
VOID endgame(VOID);
VOID updateDisplay(UBYTE);
VOID getXY(UBYTE *, UBYTE *, UBYTE *, ULONG);
VOID openAudio(VOID);
VOID openSounds(VOID);
LONG setSeek(FILE *, ULONG);
VOID playSound(struct noiz *, struct IOAudio *, struct MsgPort *);
struct Screen *scn = NULL;
struct Window *win = NULL;
struct TextFont *wFont = NULL;
struct MsgPort *RaudioMP = NULL, *LaudioMP = NULL;
struct IOAudio Raudio, Laudio;
BOOL playit = TRUE;
/*
* main() sets up the audio.device and opens the Window.
* Note: No libraries are opened and the WBStartup is not handled.
* I let SAS/C handle all that nonsense!
*/
main()
{
struct NewWindow nw = {0,11,510,175,0,1,
IDCMP_GADGETUP|IDCMP_MOUSEBUTTONS|IDCMP_CLOSEWINDOW|
IDCMP_MENUPICK, WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|
WFLG_DRAGBAR|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
&gad, NULL, NULL, NULL, NULL, 100, 11, 510, 175,
WBENCHSCREEN,
};
SHORT d;
UWORD box[6][10] = {
{9,82, 9,15, 498,15, 10,15, 10,81},
{9,153, 9,86, 498,86, 10,86, 10,152},
{475,156, 475,168, 141,168, 474,168, 474,157},
{499,15, 499,82, 10,82, 498,82, 498,16},
{499,87, 499,153, 10,153, 498,153, 498,88},
{140,168, 140,156, 474,156, 141,156, 141,167},
};
openAudio();
openSounds();
srand(VBeamPos());
if (!(scn = LockPubScreen(NULL))) closer("Could not lock screen!!");
if (win = OpenWindow(&nw)) {
if (scn->Font->ta_YSize > 8) {
wFont = OpenFont(&Topaz80);
SetFont(win->RPort, wFont);
}
strip.Width = TextLength(&win->WScreen->RastPort, "Game", 4) + 8;
SetMenuStrip(win, &strip);
SetWindowTitles(win,"⌐1994 John Corigliano","Fuzzy Battle Sheep!");
SetAPen(win->RPort, 2);
for (d = 0; d < 6; d++) {
Move(win->RPort, box[d][0], box[d][1]);
Draw(win->RPort, box[d][2], box[d][3]);
Draw(win->RPort, box[d][4], box[d][5]);
Move(win->RPort, box[d][6], box[d][7]);
Draw(win->RPort, box[d][8], box[d][9]);
if (d == 2) SetAPen(win->RPort, 1);
}
}
UnlockPubScreen(NULL, scn);
if (!win) closer("Window problem...");
wText("Press 'Set Up' to begin...");
updateDisplay(TOP);
updateDisplay(BOTTOM);
doIDCMP();
closer(NULL);
}
/*
* This clean-up function can be called from just about anywhere in the
* program.
*/
VOID closer(UBYTE *s)
{
BYTE i;
if (!Raud_dev) CloseDevice((struct IORequest *)&Raudio);
if (RaudioMP) DeletePort(RaudioMP);
if (!Laud_dev) CloseDevice((struct IORequest *)&Laudio);
if (LaudioMP) DeletePort(LaudioMP);
for (i = 0; i < 5; i++)
if (sounds[i].data) FreeMem(sounds[i].data, sounds[i].size);
if (win) {
ClearMenuStrip(win);
CloseWindow(win);
}
if (wFont) CloseFont(wFont);
if (s) puts(s);
exit(0);
}
/*
* Main message loop
*/
VOID doIDCMP(VOID)
{
BOOL done = FALSE, my_turn = FALSE;
struct IntuiMessage *imsg;
ULONG class, ans;
UWORD code, mnum, inum, snum;
UBYTE s[SLEN];
struct EasyStruct es = {
sizeof(struct EasyStruct),
0,
"Battle Sheep Note:",
"End this game?",
"Okay | Cancel",
};
while (!done) {
if ((my_turn) && (in_progress)) {
compsTurn();
my_turn = FALSE;
}
else {
Wait(1L << win->UserPort->mp_SigBit);
while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort)) {
class = imsg->Class;
code = imsg->Code;
ReplyMsg((struct Message *)imsg);
if (class == IDCMP_GADGETUP) {
if (in_progress) ans = EasyRequest(win, &es, NULL);
else ans = 1;
if (ans) {
OffGadget(&gad, win, NULL);
comp_score = 6;
endgame();
setPlayer();
SetAPen(win->RPort, 0);
RectFill(win->RPort, 15, 157, 135, 169);
OnGadget(&gad, win, NULL);
}
}
if (class == IDCMP_MOUSEBUTTONS) {
if ((code == SELECTDOWN) && in_progress && !my_turn)
my_turn = findBlock(win->MouseX, win->MouseY);
}
if (class == IDCMP_MENUPICK) {
mnum = MENUNUM(code);
inum = ITEMNUM(code);
snum = SUBNUM(code);
if (mnum == 0) {
if (inum == 0) {
think = snum;
sprintf(s,"Thinking is now %s.",tk[think]);
wText(s);
}
if (inum == 1) {
if (snum == 0) playit = FALSE;
else if (snum == 1) playit = TRUE;
}
if (inum == 3) done = TRUE;
}
}
if (class == IDCMP_CLOSEWINDOW) done = TRUE;
if (done == TRUE)
done = (EasyRequest(win, &es, NULL)) ? TRUE : FALSE;
}
}
}
while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort))
ReplyMsg((struct Message *)imsg);
}
/*
* This is where we get the player set-up. The lower grid is replaced
* with gadgets (defined in "placegads.h"). At the end, the gadgets are
* re-organized so that if the function is called again, the gadgets
* will be properly linked.
*/
VOID setPlayer(VOID)
{
BOOL done = FALSE;
struct IntuiMessage *imsg;
struct Gadget *work=NULL, *active;
UWORD cur = 0;
ULONG class;
active = &g7;
if (play_one) updateDisplay(TOP); /* First time? */
else play_one = TRUE;
SetAPen(win->RPort, 0);
RectFill(win->RPort, 15, 88, 495, 152);
AddGList(win, &g12 , (~0), 12, NULL); /* Gadget g12 is the first in */
RefreshGList(&g12, win, NULL, 12); /* the linked list of gads */
dBox(play_ships[0].Pos, CURR, PLAYER);
dBox(play_ships[1].Pos, SET, PLAYER);
dBox(play_ships[2].Pos, SET, PLAYER);
dBox(play_ships[3].Pos, SET, PLAYER);
dBox(play_ships[4].Pos, SET, PLAYER);
wText("Place your sheep...");
OffMenu(win, NOITEM);
while (!done) {
Wait(1L << win->UserPort->mp_SigBit);
while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort)) {
class = imsg->Class;
if (class == IDCMP_GADGETUP)
work = (struct Gadget *)imsg->IAddress;
ReplyMsg((struct Message *)imsg);
if (class == IDCMP_GADGETUP) {
switch (work->GadgetID) {
case UP_GAD:
moveUp(&(play_ships[cur]), cur);
break;
case DN_GAD:
moveDown(&(play_ships[cur]), cur);
break;
case LT_GAD:
moveLeft(&(play_ships[cur]), cur);
break;
case RT_GAD:
moveRight(&(play_ships[cur]), cur);
break;
case RO_GAD:
shipRotate(&(play_ships[cur]), cur);
break;
case RN_GAD:
dBox(play_ships[0].Pos, FRESH, PLAYER);
dBox(play_ships[1].Pos, FRESH, PLAYER);
dBox(play_ships[2].Pos, FRESH, PLAYER);
dBox(play_ships[3].Pos, FRESH, PLAYER);
dBox(play_ships[4].Pos, FRESH, PLAYER);
pickShips(play_ships);
dBox(play_ships[0].Pos, SET, PLAYER);
dBox(play_ships[1].Pos, SET, PLAYER);
dBox(play_ships[2].Pos, SET, PLAYER);
dBox(play_ships[3].Pos, SET, PLAYER);
dBox(play_ships[4].Pos, SET, PLAYER);
dBox(play_ships[cur].Pos, CURR, PLAYER);
break;
case QT_GAD:
done = TRUE;
break;
default:
if (work != active) {
/* Mutual exclusion nonsense! */
RemoveGList(win, active, 1);
RemoveGList(win, work, 1);
active->Flags &= ~GFLG_SELECTED;
work->Flags |= GFLG_SELECTED;
SetAPen(win->RPort, 0);
RectFill(win->RPort, active->LeftEdge,
active->TopEdge,
active->LeftEdge + 100,
active->TopEdge + 12);
RectFill(win->RPort, work->LeftEdge,
work->TopEdge,
work->LeftEdge + 100,
work->TopEdge + 12);
AddGList(win, active, (~0), 1, NULL);
AddGList(win, work, (~0), 1, NULL);
RefreshGList(work, win, NULL, 1);
RefreshGList(active, win, NULL, 1);
active = work;
dBox(play_ships[cur].Pos, SET, PLAYER);
cur = work->GadgetID - 206;
dBox(play_ships[cur].Pos, CURR, PLAYER);
}
break;
}
}
}
}
SetPointer(win, pnt, 16, 16, -6, 0);
wText("Please wait....");
dBox(play_ships[0].Pos, SET, PLAYER);
dBox(play_ships[1].Pos, SET, PLAYER);
dBox(play_ships[2].Pos, SET, PLAYER);
dBox(play_ships[3].Pos, SET, PLAYER);
dBox(play_ships[4].Pos, SET, PLAYER);
for (cur = 0; cur < 192; cur++) /* These arrays are */
player[cur] = computer[cur] = (UBYTE)cur; /* the 2 grids */
pickShips(comp_ships);
play_score = comp_score = 0;
in_progress = TRUE;
RemoveGList(win, gad.NextGadget, 12);
g1.NextGadget = NULL; /* Re-link the gadgets */
g2.NextGadget = &g1;
g3.NextGadget = &g2;
g4.NextGadget = &g3;
g5.NextGadget = &g4;
g6.NextGadget = &g5;
g7.NextGadget = &g6;
g8.NextGadget = &g7;
g9.NextGadget = &g8;
g10.NextGadget = &g9;
g11.NextGadget = &g10;
g12.NextGadget = &g11;
active->Flags &= ~GFLG_SELECTED;
g7.Flags |= GFLG_SELECTED;
updateDisplay(BOTTOM);
ClearPointer(win);
wText("It's your turn.");
OnMenu(win, NOITEM);
while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort))
ReplyMsg((struct Message *)imsg);
return;
}
/*
* Draws one or a series of boxes on either grid
*/
VOID dBox(ULONG ship, SHORT pen, UBYTE who)
{
UWORD x, y = 0, z, a = 0;
SHORT b_x[6], b_y[6], ix = 2, iy = 1, ixx = 17, iyy = 6;
ULONG r_mask = ROW_MASK, c_mask = COL_MASK;
x = 15;
for (z = 0; z < 24; z++) {
if (ship & c_mask) b_x[y++] = x;
x += 20;
c_mask >>= 1;
}
x = (who == PLAYER) ? 17 : 88;
for (z = 0; z < 8; z++)
{
if (ship & r_mask) b_y[a++] = x;
x += 8;
r_mask >>= 1;
}
if (pen == EMPTY) {
ix = iy = 0;
ixx = 19;
iyy = 7;
pen = FRESH;
}
SetAPen(win->RPort, pen);
if (y == 1)
for (x = 0; x < a; x++) {
RectFill(win->RPort,b_x[0]+ix,b_y[x]+iy,b_x[0]+ixx,b_y[x]+iyy);
}
else
for (x = 0; x < y; x++) {
RectFill(win->RPort,b_x[x]+ix,b_y[0]+iy,b_x[x]+ixx,b_y[0]+iyy);
}
return;
}
/*
* Move a ship up a row
*/
VOID moveUp(struct Ship *ship, WORD cur)
{
ULONG row = ALL_ROWS;
if (ship->Pos & ROW_MASK) return;
row &= ship->Pos;
row <<= 1;
safeDraw((ship->Pos & ALL_COLS), row, cur);
return;
}
/*
* Move a ship down a row
*/
VOID moveDown(struct Ship *ship, WORD cur)
{
ULONG row = ALL_ROWS;
if (ship->Pos & 0x01000000) return;
row &= ship->Pos;
row >>= 1;
safeDraw((ship->Pos & ALL_COLS), row, cur);
return;
}
/*
* Move a ship left one column
*/
VOID moveLeft(struct Ship *ship, WORD cur)
{
ULONG col = ALL_COLS;
if (ship->Pos & COL_MASK) return;
col &= ship->Pos;
col <<= 1;
safeDraw(col, (ship->Pos & ALL_ROWS), cur);
return;
}
/*
* Move a ship right one column
*/
VOID moveRight(struct Ship *ship, WORD cur)
{
ULONG col = ALL_COLS;
if (ship->Pos & 0x1) return;
col &= ship->Pos;
col >>= 1;
safeDraw(col, (ship->Pos & ALL_ROWS), cur);
return;
}
/*
* Turn ship 90 degrees
*/
VOID shipRotate(struct Ship *ship, WORD cur)
{
ULONG row=ALL_ROWS, col=ALL_COLS, h_check=ROW_MASK, v_check=COL_MASK;
WORD x, y;
for (x = 0; x < 24; x++) {
if (ship->Pos & v_check) break;
v_check >>= 1;
}
for (y = 0; y < 8; y++) {
if (ship->Pos & h_check) break;
h_check >>= 1;
}
if (ship->Data & HORIZ) {
if ((8 - y) < sizes[cur]) return;
}
else {
if ((24 - x) < sizes[cur]) return;
}
row = (ALL_COLS & ship->Pos) << (8 + x - y);
col = (ALL_ROWS & ship->Pos) >> (8 + x - y);
if (safeDraw(row, col, cur)) {
if (ship->Data & HORIZ) ship->Data = 0x0;
else ship->Data = 0x2;
}
return;
}
/*
* Make sure we don't draw one ship on top of another!
*/
BOOL safeDraw(ULONG col, ULONG row, WORD cur)
{
if (OK != collided(row, col, cur, play_ships)) return(FALSE);
dBox(play_ships[cur].Pos, FRESH, PLAYER);
play_ships[cur].Pos = row | col;
dBox(play_ships[cur].Pos, CURR, PLAYER);
return(TRUE);
}
/*
* Is there a ship at this position?
*/
UBYTE collided(ULONG col, ULONG row, WORD cur, struct Ship *s)
{
UBYTE x;
for (x = 0; x < 5; x++) {
if (x != cur) {
if (((s[x]).Pos & row) && ((s[x]).Pos & col))
return(x);
}
}
return(OK);
}
/*
* Randomly position five ship
*/
VOID pickShips(struct Ship *ships)
{
UWORD ran, row, col, orien, touch = 1;
UBYTE x, ct;
ULONG r_mask, c_mask;
BOOL fail;
touch = (UWORD)getRand(250);
touch = (touch <= 125) ? 0 : 1; /* Will the ships touch? */
for (ct = 0; ct < 5; ct++) {
do {
orien = (UWORD)getRand(250);
orien = (orien <= 125) ? 0 : 1;
fail = FALSE;
ran = (UWORD)getRand(SQUARES);
row = GET_ROW(ran);
col = GET_COL(ran);
if (orien == 1)
while (row > (8-sizes[ct])) row -= 1;
else
while (col > (24 - sizes[ct])) col -= 1;
r_mask = ROW_MASK >> (row-1);
c_mask = COL_MASK >> (col-1);
for (x = 0; x < (sizes[ct] - 1); x++) {
if (orien == 1) r_mask |= r_mask >> 1;
else c_mask |= c_mask >> 1;
}
if (OK != collided(r_mask, c_mask, ct, ships)) fail = TRUE;
if (touch) {
if (OK != collided(r_mask>>1,c_mask, ct, ships)) fail=TRUE;
if (OK != collided(r_mask<<1,c_mask, ct, ships)) fail=TRUE;
if (OK != collided(r_mask,c_mask>>1, ct, ships)) fail=TRUE;
if (OK != collided(r_mask,c_mask<<1, ct, ships)) fail=TRUE;
}
} while (fail);
ships[ct].Pos = r_mask | c_mask;
if (orien == 1) ships[ct].Data = 0x0;
else ships[ct].Data = 0x2;
}
return;
}
/*
* My function that picks a pseudo-random number between zero and max
*/
LONG getRand(LONG max)
{
LONG z;
do {
z = rand();
while (z > max) z %= max;
} while (z < 0);
return(z + 1);
}
/*
* Updates the grid and if there was a hit, it returns a number
* between 0 and 4 that corresponds to an array of struct Ship.
* i.e. play_ships[x]
* If not a hit, returns OK
*/
UBYTE findHit(struct Ship *them, ULONG ship, UBYTE who)
{
UBYTE x;
if (OK != (x = collided(ALL_ROWS & ship, ALL_COLS & ship, OK, them))) {
dBox(ship, CURR, who);
return(x);
}
else {
dBox(ship, EMPTY, who);
return (OK);
}
}
/*
* Interprets mouseX and mouseY. Also determines if the player hit
* or missed.
*/
BOOL findBlock(UWORD x, UWORD y)
{
UWORD i, j, k = 1, pos = 0;
UBYTE ct;
UBYTE hit_mask = 0x80, s[SLEN];
if ((x < 15) || (x > 495) || (y < 88) || (y > 152)) return(FALSE);
for (i = 88; i <= 144; i += 8) {
for (j = 15; j <= 475; j += 20, k++) {
if (((x >= j) && (x <= (j+19))) && ((y >= i) && (y<= (i+7)))) {
pos = k;
break;
}
}
if (pos) break;
}
pos -= 1;
if (computer[pos] >= HIT) return(FALSE);
if (OK != (ct = findHit(comp_ships, MAKE_SHIP(computer[pos]), COMP))) {
for (j = 1; j <= sizes[ct]; j++) {
if (!(comp_ships[ct].Data & hit_mask)) break;
hit_mask >>= 1;
}
comp_ships[ct].Data |= hit_mask;
if ((dead_masks[ct] & comp_ships[ct].Data) == dead_masks[ct]) {
dBox(comp_ships[ct].Pos, KILL, COMP);
comp_ships[ct].Data |= 0x1;
i = ((UWORD)getRand(17)) - 1;
sprintf(s, "You %s %s!!!", verbs[i], Pnames[ct]);
wText(s);
if (playit) playSound(&sounds[3], &Laudio, LaudioMP);
play_score += 1;
}
else if (playit) playSound(&sounds[0], &Laudio, LaudioMP);
computer[pos] = HIT;
endgame();
}
else {
computer[pos] = MISS;
if (playit) playSound(&sounds[2], &Laudio, LaudioMP);
}
return (TRUE);
}
/*
* Centers a string of text and prints it.
*/
VOID wText(UBYTE *s)
{
UBYTE word[SLEN], len, lj, rj, j, k = 0;
UWORD i;
len = strlen(s);
if (!len) return;
len = (len > SLEN-1) ? SLEN-1 : len;
lj = ((SLEN - 1) - len) / 2;
rj = ((SLEN - 1) - len) - lj;
for(i = 0; i < lj; i++) word[i] = ' ';
for(j = i; j < lj + len; j++) word[j] = s[k++];
for(i = j; i < SLEN-1; i++) word[i] = ' ';
word[SLEN-1] = '\0';
SetAPen(win->RPort, 1);
Move(win->RPort, 155, 165);
Text(win->RPort, word, SLEN - 1);
return;
}
/*
* My very own interpretation of Fuzzy Logic! This function simply
* evaluates each square's membership in a (fictional) Fuzzy Set.
* The stronger the membership, the more likely the computer will be
* to select it. Membership is determined by:
* 1) Empty? = No Membership
* 2) Neighbors = Membership
* 3) Neighbors are HITs = Strongest Membership
* Note: a HIT is a ship UNDER ATTACK.
*/
VOID compsTurn(VOID)
{
#define COL_A(a) (a==0||a==24||a==48||a==72||a==96||a==120||a==144||a==168)
#define COL_B(a) (a==1||a==25||a==49||a==73||a==97||a==121||a==145||a==167)
#define COL_Y(a) (a==22||a==46||a==70||a==94||a==118||a==142||a==166||a==190)
#define COL_Z(a) (a==23||a==47||a==71||a==95||a==119||a==143||a==167||a==191)
#define ROW_A(a) (a < 24)
#define ROW_B(a) ((a < 48) && (a > 23))
#define ROW_Y(a) ((a < 168) && (a > 143))
#define ROW_Z(a) (a > 167)
UBYTE r = 0, row, col, hit_mask = 0x80, s[SLEN], num, i;
UBYTE sets[SQUARES], max;
ULONG row_mask, col_mask;
if (think == 0) { /* No logic - random pick */
while (!r) {
r = (UBYTE)getRand(SQUARES) - 1;
if (player[r] >= HIT) r = 0;
}
}
else {
if (!(play_ships[4].Data & 1)) max = 2; /* Find shortest */
else if (!(play_ships[3].Data & 1)) max = 3; /* ship. Squares */
else if (!(play_ships[2].Data & 1)) max = 4; /* that have < max */
else if (!(play_ships[1].Data & 1)) max = 5; /* can't be members*/
else max = 6;
for (i = 0; i < SQUARES; i++) {
sets[i] = 0; /* Start with a membership of zero */
if ((findShort(player[i], max)) && (player[i] < HIT)) {
/* Increase membership for HITs */
if ((!ROW_A(i)) && (player[i-24] == HIT)) {
sets[i] += 10;
if ((!ROW_B(i)) && (player[i-48] == HIT)) sets[i]+=20;
}
if ((!ROW_Z(i)) && (player[i+24] == HIT)) {
sets[i] += 10;
if ((!ROW_Y(i)) && (player[i+48] == HIT)) sets[i]+=20;
}
if ((!COL_A(i)) && (player[i-1] == HIT)) {
sets[i] += 10;
if ((!COL_B(i)) && (player[i-2] == HIT)) sets[i]+=20;
}
if ((!COL_Z(i)) && (player[i+1] == HIT)) {
sets[i] += 10;
if ((!COL_Y(i))&&(player[i+2] == HIT)) sets[i]+=20;
}
if ((think == 2) && (sets[i] == 0)) {
num = 0;
/* Increase membership for neighbors */
if ((!ROW_A(i)) && (player[i-24] < HIT)) num++;
if ((!ROW_Z(i)) && (player[i+24] < HIT)) num++;
if ((!COL_A(i)) && (player[i-1] < HIT)) num++;
if ((!COL_Z(i)) && (player[i+1] < HIT)) num++;
if (ROW_A(i) || ROW_Z(i) || COL_A(i) || COL_Z(i))
sets[i] += (num + 1);
else sets[i] += num;
}
}
}
max = r = 0;
for (i = 0; i < SQUARES; i++) { /* Find strongest members */
if (sets[i] > max) {
max = sets[i];
r = i;
}
}
if ((max > 0) && (max < 10)) { /* No HITs, but neighbors */
do { /* Randomly select */
i = (UBYTE)getRand(SQUARES) - 1; /* a member with max */
} while (sets[i] != max); /* neighbors */
r = i;
}
else if (max == 0) { /* Should never get here! */
r = 0; /* No members! Ack! */
while (!r) {
r = (UBYTE)getRand(SQUARES) - 1;
if (player[r] >= HIT) r = 0;
}
}
}
row_mask = ROW_MASK >> (GET_ROW(player[r]) - 1);
col_mask = COL_MASK >> (GET_COL(player[r]) - 1);
if (OK != (max = findHit(play_ships, row_mask|col_mask, PLAYER))) {
for (i = 1; i <= sizes[max]; i++) {
if (!(play_ships[max].Data & hit_mask)) break;
hit_mask >>= 1;
}
play_ships[max].Data |= hit_mask;
if ((dead_masks[max] & play_ships[max].Data) == dead_masks[max]) {
play_ships[max].Data |= 0x1;
dBox(play_ships[max].Pos, KILL, PLAYER);
if (play_ships[max].Data & HORIZ) {
col_mask = COL_MASK;
while (!(col_mask & play_ships[max].Pos)) col_mask >>= 1;
for (i = 0; i < sizes[max]; i++) {
getXY(&row, &col, &num, row_mask|col_mask);
player[num] = SUNK;
col_mask >>= 1;
}
}
else {
row_mask = ROW_MASK;
while (!(row_mask & play_ships[max].Pos)) row_mask >>= 1;
for (i = 0; i < sizes[max]; i++) {
getXY(&row, &col, &num, row_mask|col_mask);
player[num] = SUNK;
row_mask >>= 1;
}
}
i = ((UWORD)getRand(17)) - 1;
sprintf(s, "I %s %s!!!", verbs[i], Cnames[max]);
wText(s);
if (playit) playSound(&sounds[4], &Raudio, RaudioMP);
comp_score += 1;
}
else {
player[r] = HIT;
if (playit) playSound(&sounds[0], &Raudio, RaudioMP);
}
endgame();
}
else {
player[r] = MISS;
if (playit) playSound(&sounds[1], &Raudio, RaudioMP);
}
return;
}
/*
* Checks horizontally and vertically for neighbors
*/
BOOL findShort(UBYTE number, WORD shortest)
{
WORD i, j;
UBYTE up_ct, dn_ct, lt_ct, rt_ct, row, col;
up_ct = dn_ct = lt_ct = rt_ct = 0;
row = GET_ROW(number);
col = GET_COL(number);
if (row != 1) {
j = number - (24 * (row - 1));
for (i = number - 24; i >= j; i -= 24) {
if (player[i] >= MISS) break;
up_ct += 1;
}
}
if (row != 8) {
j = number + (24 * (8 - row));
for (i = number + 24; i <= j; i += 24) {
if (player[i] >= MISS) break;
dn_ct += 1;
}
}
if (col != 1) {
j = number - (col - 1);
for (i = number - 1; i >= j; i--) {
if (player[i] >= MISS) break;
lt_ct += 1;
}
}
if (col != 24) {
j = (24 * row) - 1;
for (i = number + 1; i <= j; i++) {
if (player[i] >= MISS) break;
rt_ct += 1;
}
}
if (((lt_ct + rt_ct + 1)< shortest) && ((up_ct + dn_ct + 1)< shortest))
return(FALSE);
else
return(TRUE);
}
/*
* Checks to see if the game has ended
*/
VOID endgame(VOID)
{
UBYTE x, y, ro, co, o;
ULONG rm, cm;
if (comp_score == 5) {
wText("I win!!!!");
for (x = 0; x < 5; x++) {
if (!(comp_ships[x].Data & 1)) {
if (comp_ships[x].Data & HORIZ) {
rm = comp_ships[x].Pos & ALL_ROWS;
cm = COL_MASK;
while (!(cm & comp_ships[x].Pos)) cm >>= 1;
for (y = 0; y < sizes[x]; y++) {
getXY(&ro, &co, &o, rm|cm);
if (computer[o] < HIT) dBox(rm|cm, SET, COMP);
cm >>= 1;
}
}
else {
rm = ROW_MASK;
cm = comp_ships[x].Pos & ALL_COLS;
while (!(rm & comp_ships[x].Pos)) rm >>= 1;
for (y = 0; y < sizes[x]; y++) {
getXY(&ro, &co, &o, rm|cm);
if (computer[o] < HIT) dBox(rm|cm, SET, COMP);
rm >>= 1;
}
}
}
}
}
if (play_score == 5) wText("Arghh! You won!");
if ((play_score >= 5) || (comp_score >= 5)) {
for (x = 0; x < 5; x++) {
play_ships[x].Data &= 0x2;
comp_ships[x].Data = 0x0;
comp_ships[x].Pos = 0x0;
}
comp_score = play_score = 0;
in_progress = FALSE;
}
return;
}
/*
* Redraws grid
*/
VOID updateDisplay(UBYTE side)
{
UWORD x, y;
UWORD y1 = 17, y2 = 81;
SetDrMd(win->RPort, JAM2);
SetAPen(win->RPort, 0);
if (side == BOTTOM) {
y1 = 88;
y2 = 152;
}
RectFill(win->RPort, 15, y1, 495, y2);
SetAPen(win->RPort, 2);
for (x = 15; x <= 475; x += 20) {
Move(win->RPort, x, y1);
Draw(win->RPort, x, y2 - 1);
Move(win->RPort, x+1, y1);
Draw(win->RPort, x+1, y2 - 2);
}
for (y = y1; y <= (y2 - 8); y += 8) {
Move(win->RPort, 15, y);
Draw(win->RPort, 493,y);
}
SetAPen(win->RPort, 1);
for (x = 34; x <= 494; x += 20) {
for (y = y1; y <= (y2 - 8); y += 8) {
Move(win->RPort, x, y);
Draw(win->RPort, x, y+7);
Draw(win->RPort, x-18, y+7);
Move(win->RPort, x-1, y+1);
Draw(win->RPort, x-1, y+6);
}
}
return;
}
/*
* Converts a ULONG (i.e. struct Ship.Pos) to row, column, and ordinal
* number.
* Example 0x80800000 = 10000000100000000000000000000000 binary
* which corresponds to ^row 1 ^column 1
* which would be player[0] or computer[0]
*/
VOID getXY(UBYTE *r, UBYTE *c, UBYTE *ord, ULONG comp)
{
UBYTE i;
ULONG row_mask = ROW_MASK, col_mask = COL_MASK;
for (i = 1; i <= 8; i++) {
if (comp & row_mask) break;
row_mask >>= 1;
}
*r = i;
for (i = 1; i <= 24; i++) {
if (comp & col_mask) break;
col_mask >>= 1;
}
*c = i;
*ord = (((*r - 1) * 24) + *c) - 1;
return;
}
/*
* Open audio.device and allocate one left channel and one right channel
*/
VOID openAudio(VOID)
{
UBYTE Rchan[] = { 0x1, 0x8 }, Lchan[] = { 0x2, 0x4};
if (!(RaudioMP = CreatePort(0, 0))) return;
Raudio.ioa_Request.io_Command = ADCMD_ALLOCATE;
Raudio.ioa_Request.io_Message.mn_ReplyPort = RaudioMP;
Raudio.ioa_Request.io_Message.mn_Node.ln_Pri = 120;
Raudio.ioa_Request.io_Flags = ADIOF_NOWAIT;
Raudio.ioa_AllocKey = 0;
Raudio.ioa_Data = Rchan;
Raudio.ioa_Length = sizeof(Rchan);
Raud_dev = OpenDevice(AUDIONAME, 0L, (struct IORequest *)&Raudio, 0L);
if (Raud_dev) {
DeletePort(RaudioMP);
RaudioMP = NULL;
}
Raudio.ioa_Request.io_Command = CMD_WRITE;
Raudio.ioa_Request.io_Flags |= ADIOF_PERVOL;
Raudio.ioa_Volume = 60;
Raudio.ioa_Cycles = 1;
if (!(LaudioMP = CreatePort(0, 0))) return;
Laudio.ioa_Request.io_Command = ADCMD_ALLOCATE;
Laudio.ioa_Request.io_Message.mn_ReplyPort = LaudioMP;
Laudio.ioa_Request.io_Message.mn_Node.ln_Pri = 120;
Laudio.ioa_Request.io_Flags = ADIOF_NOWAIT;
Laudio.ioa_AllocKey = 0;
Laudio.ioa_Data = Lchan;
Laudio.ioa_Length = sizeof(Lchan);
Laud_dev = OpenDevice(AUDIONAME, 0L, (struct IORequest *)&Laudio, 0L);
if (Laud_dev) {
DeletePort(LaudioMP);
LaudioMP = NULL;
}
Laudio.ioa_Request.io_Command = CMD_WRITE;
Laudio.ioa_Request.io_Flags |= ADIOF_PERVOL;
Laudio.ioa_Volume = 60;
Laudio.ioa_Cycles = 1;
return;
}
/*
* Read 8VSX sound samples into memory
*/
VOID openSounds(VOID)
{
#define ID_BODY MakeID('B', 'O', 'D', 'Y')
#define ID_VHDR MakeID('V', 'H', 'D', 'R')
FILE *fi;
LONG fi_seek;
UBYTE i;
struct Voice8Header {
ULONG oneShotHiSamples;
ULONG repeatHiSamples;
ULONG samplesPerHiCycle;
UWORD samplePerSec;
UBYTE ctOctave;
UBYTE sCompression;
LONG volume;
} vhdr;
for (i = 0; i < 5; i++) {
if (fi = fopen(sounds[i].name, "rb")) {
fi_seek = setSeek(fi, ID_VHDR);
if (fi_seek != -1) {
fseek(fi, fi_seek + 8, SEEK_SET);
fread((VOID *)&vhdr, 1, sizeof(struct Voice8Header), fi);
sounds[i].SPS = vhdr.samplePerSec;
sounds[i].size = vhdr.oneShotHiSamples;
if (!sounds[i].size) sounds[i].size = vhdr.repeatHiSamples;
fi_seek = setSeek(fi, ID_BODY);
if (fi_seek != -1) {
fseek(fi, fi_seek + 8, SEEK_SET);
sounds[i].data = AllocMem(sounds[i].size, MEMF_CHIP);
fread((VOID *)sounds[i].data, 1, sounds[i].size, fi);
}
}
fclose(fi);
}
}
return;
}
/*
* Find a Chunk ID in an IFF file
*/
LONG setSeek(FILE *sf, ULONG ID)
{
WORD ct, i;
BOOL test = FALSE;
LONG byts = 0, seek = 0;
UBYTE buf[1024];
rewind(sf);
ct = fread((VOID *)buf, 1, 1024, sf);
while (1) {
for (i = 0; i < ct; i++) {
if (MakeID(buf[i],buf[i+1],buf[i+2],buf[i+3]) == ID) {
test = TRUE;
break;
}
}
if (test || feof(sf)) break;
ct = fread(buf, 1, 1024, sf);
byts += ct;
}
seek = byts + i;
if (test) return(seek);
else return(-1);
}
/*
* Play an 8VSX sound sample
*/
VOID playSound(struct noiz *nz, struct IOAudio *io_p, struct MsgPort *port)
{
struct Message *msg;
if (!port) return;
if (!nz->data) return;
if (GfxBase->DisplayFlags & PAL)
io_p->ioa_Period = PAL_CLOCK / nz->SPS;
else
io_p->ioa_Period = NTSC_CLOCK / nz->SPS;
io_p->ioa_Data = (UBYTE *)nz->data;
io_p->ioa_Length = nz->size;
BeginIO((struct IORequest *)io_p);
WaitPort(port);
msg = GetMsg(port);
return;
}